AI 기반 소프트웨어 개발과 결정론적 오라클의 모색

AI 기반 소프트웨어 개발과 결정론적 오라클의 모색

확률적 혼돈 속에서 공학적 엄밀함을 찾아서

1. 서문: 소프트웨어 2.0 시대, 엔지니어링의 재정의

1.1 패러다임의 거대한 전환: 명시적 논리에서 확률적 추론으로

소프트웨어 엔지니어링의 역사는 곧 ’제어(Control)’의 역사였습니다. 지난 반세기 동안 프로그래머는 전지전능한 설계자로서 시스템의 모든 상태(State)와 전이(Transition)를 통제했습니다. 우리가 작성한 if-then-else 구문은 디지털 세계의 물리 법칙이었으며, 컴파일러는 그 법칙을 엄격하게 집행하는 집행관이었습니다. 이 세계에서 ’버그’란 논리의 결함이었고, ’테스팅’은 입력 x에 대해 출력 y가 정확히 도출되는지를 확인하는 결정론적(Deterministic) 과정이었습니다.

그러나 대규모 언어 모델(LLM)과 생성형 AI의 등장은 이 견고했던 세계관을 송두리째 뒤흔들고 있습니다. 안드레아 카르파시(Andrej Karpathy)가 주창한 ’소프트웨어 2.0(Software 2.0)’의 시대가 도래하면서, 우리는 더 이상 명시적인 코드로 논리를 작성하지 않습니다. 대신 우리는 거대한 데이터의 패턴을 학습한 신경망에 ’프롬프트(Prompt)’라는 불완전하고 모호한 자연어를 통해 우리의 의도(Intent)를 전달합니다.

이 새로운 패러다임에서 소프트웨어의 동작은 명확한 인과관계가 아닌, 고차원 벡터 공간에서의 확률적 추론(Probabilistic Inference) 결과로 나타납니다. 이는 엔지니어링의 본질적인 위기를 초래합니다. 입력이 같아도 출력은 매번 달라질 수 있으며, 시스템의 내부 동작은 블랙박스 속에 감춰져 있습니다. “이 함수는 항상 정수를 반환한다“는 명제는 이제 “이 모델은 95%의 확률로 숫자를 포함한 텍스트를 생성할 것이다“라는 불확실한 추측으로 대체되었습니다.

본 서적은 바로 이 지점, 즉 “확률적 본성을 지닌 AI 시스템 위에서 어떻게 결정론적 신뢰(Deterministic Reliability)를 구축할 것인가?” 라는 거대한 엔지니어링적 난제에 답하기 위해 기획되었습니다. 우리는 이 책을 통해 무작위성(Randomness)을 공학적으로 통제하고, 모호한 자연어 출력을 검증 가능한 구조로 구속하며, 궁극적으로는 AI를 신뢰할 수 있는 엔터프라이즈 시스템의 부품으로 안착시키는 방법론을 탐구할 것입니다.

1.2 비결정성의 심연: 하드웨어와 시스템의 관점에서

많은 개발자들과 연구자들은 LLM의 비결정성(Non-determinism)을 단순히 모델의 생성 파라미터, 즉 temperature 설정의 문제로 치부하곤 합니다. “Temperature를 0으로 설정하면 결정론적인 결과를 얻을 수 있다“는 믿음은 AI 엔지니어링 분야의 가장 널리 퍼진 오해 중 하나입니다. 이 책의 초반부에서는 이러한 표면적인 이해를 넘어, 비결정성이 발생하는 물리적이고 시스템적인 근원을 집요하게 추적합니다. 최신 연구들은 LLM의 무작위성이 소프트웨어 설정을 넘어선 하드웨어 아키텍처, 특히 GPU의 병렬 연산 방식에서 기인함을 보여줍니다.

1.2.1 실리콘 레벨의 무작위성: 부동소수점 비결합성

우리가 사용하는 컴퓨터의 수학은 완벽하지 않습니다. 특히 실수 연산에서 사용하는 부동소수점(Floating-Point) 방식은 근본적인 한계를 지니고 있습니다. 수학적으로 실수의 덧셈은 결합법칙이 성립합니다. 즉, (a + b) + ca + (b + c)와 언제나 같아야 합니다. 그러나 컴퓨터의 부동소수점 연산에서는 유한한 정밀도(Precision)로 인해 이 법칙이 깨집니다.

현대의 LLM은 수십억 개의 파라미터를 계산하기 위해 GPU(Graphics Processing Unit)를 사용합니다. GPU는 수천 개의 코어가 동시에 작동하는 거대한 병렬 계산기입니다. 딥러닝의 핵심 연산인 행렬 곱셈이나 어텐션(Attention) 메커니즘을 수행할 때, GPU는 효율성을 극대화하기 위해 수많은 값을 동시에 더하는 ‘리덕션(Reduction)’ 과정을 거칩니다. 이때 각 코어가 작업을 완료하는 순서는 미세한 환경 요인—GPU의 온도, 전력 공급 상태, 메모리 버스의 혼잡도, 다른 프로세스와의 컨텍스트 스위칭 등—에 따라 매 순간 달라집니다.

연산 순서가 바뀌면 부동소수점의 반올림 오차(Rounding Error)가 누적되는 방식이 달라집니다. 비록 그 차이가 소수점 아래 수십 번째 자리의 미세한 값이라 할지라도, LLM과 같이 깊은 층(Layer)을 가진 신경망에서는 이 오차가 층을 거듭할수록 증폭됩니다. 이를 ’나비 효과’에 비유할 수 있습니다. 입력단에서의 극미한 수치 변동은 최종 출력단인 로짓(Logit) 값에 유의미한 변화를 일으키고, 이는 결국 토큰 선택 확률을 뒤바꾸어 완전히 다른 문장을 생성하게 만듭니다.

1.2.2 배치 의존성과 스케줄링의 카오스

비결정성의 또 다른 주범은 서버 측의 최적화 기법인 ‘동적 배칭(Dynamic Batching)’ 입니다. 추론 서버는 처리량(Throughput)을 높이기 위해 서로 다른 사용자의 요청을 하나의 배치(Batch)로 묶어 처리합니다. 이때 내 요청이 어떤 다른 요청들과 함께 묶이느냐에 따라 연산의 패턴과 메모리 접근 순서가 달라집니다. 이를 ’배치 의존성(Batch Dependence)’이라고 합니다.

예를 들어, 긴 문맥을 가진 요청 A와 짧은 문맥을 가진 요청 B가 함께 처리될 때와, 요청 A가 요청 C와 함께 처리될 때, GPU 내부의 커널(Kernel) 실행 경로는 달라질 수 있습니다. 특히 최근 도입된 ‘전문가 혼합(Mixture of Experts, MoE)’ 모델은 입력 토큰에 따라 활성화되는 전문가 네트워크가 동적으로 변하기 때문에, 분산 시스템 상에서의 통신 지연이나 로드 밸런싱의 미세한 차이조차 결과에 영향을 미칩니다.

이 책은 이러한 하드웨어적, 시스템적 비결정성을 ’공학적으로 제어 가능한 변수’로 만들기 위한 최전선의 연구들을 소개합니다. 배치 크기와 상관없이 동일한 연산 순서를 보장하는 ‘배치 불변(Batch-Invariant) 커널’ 설계부터, 결정론적 추론을 위한 새로운 스케줄링 알고리즘인 ‘LLM-42’ 와 같은 혁신적인 시도들을 다룹니다. 독자들은 이를 통해 단순히 random_seed를 고정하는 것을 넘어, 시스템 아키텍처 수준에서 재현 가능성(Reproducibility)을 확보하는 깊이 있는 통찰을 얻게 될 것입니다.

1.3 오라클의 상실과 재정의: 확률을 검증하는 기술

소프트웨어 테스팅 이론에서 ‘오라클(Oracle)’ 은 시스템의 실행 결과가 올바른지 판단하는 절대적인 기준을 의미합니다. 전통적인 소프트웨어 공학에서 오라클은 명확했습니다. 계산기 프로그램에 2+2를 입력하면 4가 나와야 한다는 것은 논란의 여지가 없는 진리(Ground Truth)였습니다. 그러나 AI 시대, 특히 생성형 모델의 시대에 이 ’진리’의 개념은 붕괴하고 있습니다.

1.3.1 오라클 문제 (The Oracle Problem)의 심화

“이 고객 불만 메일을 정중하게 요약해줘“라는 요청에 대한 정답은 무엇일까요? 단 하나의 정답은 존재하지 않습니다. 수만 가지의 ‘적절한’ 요약과 수만 가지의 ‘부적절한’ 요약이 존재할 뿐입니다. 이를 ‘오라클 문제(The Oracle Problem)’ 라고 합니다. 기대 출력(Expected Output)을 사전에 정의할 수 없거나 정의하는 데 비용이 너무 많이 드는 상황에서, 우리는 어떻게 소프트웨어의 품질을 보증할 수 있을까요?

LLM은 환각(Hallucination), 논리적 불일치(Logical Inconsistency), 편향된 출력 등 예측하기 어려운 오류를 범할 수 있습니다. 전통적인 단위 테스트(Unit Test)나 문자열 일치(Exact Match) 방식은 이러한 확률적 출력 앞에서는 무력합니다. 우리는 새로운 검증 패러다임이 필요합니다.

1.3.2 결정론적 오라클을 넘어서: 확률적 검증 기법

이 책은 전통적 오라클의 대안으로 ‘확률적 오라클(Probabilistic Oracle)’‘근사 오라클(Approximate Oracle)’ 의 유형학(Typology)을 제시합니다.

  1. 회귀 오라클 (Regression Oracle): 절대적인 정답은 알 수 없더라도, 시스템이 ’이전보다 나빠지지 않았음’을 검증합니다. 모델 업데이트 전후의 출력 분포를 비교하거나, 동일한 프롬프트에 대한 응답의 일관성을 측정합니다.
  2. 메타모픽 오라클 (Metamorphic Oracle): 입력 데이터의 변환에 따른 출력의 관계를 검증합니다. 예를 들어, “이 문장의 감정을 분석하라“는 요청에 대해, 입력 문장의 주어만 바꾸었을 때 감정 분석 결과가 급격히 변한다면 이는 오류일 가능성이 높습니다. 정답 자체는 몰라도, 정답이 가져야 할 불변의 속성(Invariant)을 검증하는 것입니다.
  3. 검증 가능한 오라클 (Verifiable Oracle): LLM의 출력을 기호적(Symbolic) 검증기나 정적 분석 도구로 전달하여 수학적/논리적 오류를 잡아냅니다. 자연어 출력을 코드나 논리식으로 변환한 뒤, 이를 형식 검증(Formal Verification) 도구로 확인하는 하이브리드 접근 방식입니다.

1.3.3 심판으로서의 LLM (LLM-as-a-Judge)

최근 AI 엔지니어링의 표준으로 자리 잡고 있는 ‘LLM-as-a-Judge’ 패러다임은 이 오라클 문제를 해결하기 위한 가장 실용적인 접근법 중 하나입니다. GPT-4와 같은 고성능 모델을 ’심판’으로 활용하여, 경량화 모델이나 에이전트의 출력을 평가하게 하는 것입니다.

이 방식은 인간 평가와 높은 상관관계를 보이며 확장성이 뛰어나지만, 동시에 새로운 위험을 내포하고 있습니다. 심판 모델 자체의 편향(Bias), 특히 자신이 생성한 텍스트와 유사한 스타일을 선호하는 ‘자기 선호(Self-preference)’ 편향이나, 위치 편향(Positional Bias) 등이 그것입니다. 본 서적에서는 이러한 편향을 최소화하기 위한 ‘쌍별 비교(Pairwise Comparison)’, ‘참조 기반 채점(Reference-based Grading)’, ‘CoT(Chain-of-Thought) 평가’ 등 고도화된 평가 기법을 상세히 다룹니다.

또한, 오라클 데이터베이스와 같은 엔터프라이즈 환경에서의 SQL 생성 및 실행 검증 사례를 통해, 자연어를 구조화된 쿼리 언어(SQL)로 변환하고 이를 실제 데이터베이스 엔진에서 실행하여 결과를 검증하는 ‘실행 기반 오라클(Execution-based Oracle)’ 의 개념도 소개합니다. 이는 텍스트 생성의 모호함을 실행 가능한 코드의 명확함으로 치환하여 검증 가능성을 확보하는 강력한 전략입니다.

1.4 신뢰성 공학: 구조화된 출력과 하이브리드 아키텍처

우리는 확률적 혼돈을 제어하기 위해 시스템 아키텍처 레벨에서 어떤 전략을 취해야 할까요? 해답은 ‘구속(Constraint)’‘순환(Loop)’ 에 있습니다.

1.4.1 구조화된 출력의 혁명 (Structured Outputs)

자연어의 모호함을 통제하는 가장 확실한 방법은 출력을 기계가 이해할 수 있는 엄격한 구조(JSON, XML, YAML)로 강제하는 것입니다. 최근 OpenAI의 ‘Structured Outputs’ 이나 구글의 JSON 모드 등은 단순한 편의 기능을 넘어 신뢰성 공학의 핵심 도구가 되었습니다.

JSON 스키마(JSON Schema)를 통해 우리는 모델에게 “반드시 이 키(Key)와 값(Value) 타입을 준수하라“는 강력한 제약 조건을 부여할 수 있습니다. 이는 ‘제약된 디코딩(Constrained Decoding)’ 기술을 통해 구현됩니다. 추론 과정에서 모델이 스키마에 정의되지 않은 토큰을 생성하려고 하면, 그 확률을 0으로 만들어버림으로써 문법적으로 완벽한 JSON 생성을 보장합니다. 이 기술은 ’파싱 에러’라는 고질적인 문제를 해결하고, AI 컴포넌트를 기존의 결정론적 소프트웨어 파이프라인에 안전하게 결합할 수 있게 합니다.

1.4.2 하이브리드 오라클과 자가 수정 루프

결정론적 오라클의 이상을 실현하기 위해 우리는 ‘하이브리드 아키텍처(Hybrid Architecture)’ 로 나아가야 합니다.

  1. 생성(Generation): 창의적이고 유연한 LLM이 코드, 쿼리, 또는 계획을 생성합니다.
  2. 실행 및 검증(Execution & Verification): 생성된 결과물을 샌드박스 환경에서 실제로 실행하거나(Unit Test, SQL Execution), 정적 분석기(Linter, Type Checker)로 검증합니다.
  3. 피드백 및 수정(Feedback & Correction): 실행 결과나 에러 메시지를 다시 LLM에게 입력으로 제공하여 스스로 오류를 수정하게 합니다.

‘생성-검증-수정(Generate-Verify-Correct)’ 루프는 단일 LLM 호출보다 기하급수적으로 높은 신뢰성을 보장합니다. 최근 유행하는 ’바이브 코딩(Vibe Coding)’이 직관에 의존한다면, 하이브리드 오라클은 이를 엔지니어링의 영역으로 끌어올려 시스템의 견고함을 보장합니다. 우리는 이것이 미래의 소프트웨어 개발 방법론의 표준이 될 것이라 확신합니다.

1.5 기술적 부채와 지속 가능한 AI 아키텍처

구글의 기념비적인 논문 “기계학습 시스템의 숨겨진 기술적 부채(Hidden Technical Debt in Machine Learning Systems)“가 경고했듯, AI 시스템은 전통적인 코드보다 훨씬 더 복잡하고 은밀한 기술적 부채를 쌓습니다.

1.5.1 얽힘(Entanglement)과 데이터 의존성

가장 큰 위협은 ‘얽힘(Entanglement)’ 현상입니다. AI 시스템에서는 “무엇 하나를 바꾸면 모든 것이 변합니다(Changing Anything Changes Everything, CACE)”. 입력 데이터의 분포가 미세하게 변하거나, 모델의 하이퍼파라미터 하나를 수정하면, 전혀 관련 없어 보이는 하위 시스템의 성능이 급격히 저하될 수 있습니다.

데이터 의존성(Data Dependency) 또한 심각한 문제입니다. 코드의 의존성은 컴파일러가 잡아낼 수 있지만, 데이터의 의존성은 눈에 보이지 않습니다. 특정 데이터 소스가 중단되거나 형식이 변경되었을 때, 모델은 에러를 뱉는 대신 조용히 잘못된 예측을 내놓기 시작합니다. 이는 ’침묵의 실패(Silent Failure)’를 야기하며, 시스템의 유지보수를 악몽으로 만듭니다.

1.5.2 부채 상환을 위한 아키텍처 전략

이 책은 이러한 AI 특유의 기술적 부채를 관리하고 상환하기 위한 아키텍처 전략을 제시합니다.

  • 격리(Isolation): AI 컴포넌트를 비즈니스 로직과 철저히 분리하고, 명확한 API 계약(Contract)을 통해 통신하게 합니다.
  • 관측 가능성(Observability): 단순한 시스템 가동 시간(Uptime)이나 레이턴시(Latency)가 아닌, 모델의 데이터 드리프트(Data Drift), 확신도(Confidence), 피처 중요도(Feature Importance) 변화를 실시간으로 추적해야 합니다.
  • 파이프라인의 결정론화: 데이터 전처리부터 모델 학습, 배포에 이르는 MLOps 파이프라인 전체를 코드화(Infrastructure as Code)하고 버전 관리함으로써, 언제든 과거의 상태를 완벽하게 재현할 수 있어야 합니다.

1.6 결론: 검증 가능한 AI(Verifiable AI)를 향하여

우리는 지금 소프트웨어 엔지니어링의 역사에서 가장 흥미롭고도 위험한 시기를 지나고 있습니다. AI는 우리에게 무한한 가능성을 열어주었지만, 동시에 ’신뢰’라는 가장 기본적인 가치를 위협하고 있습니다.

이 책은 단순히 LLM을 사용하는 방법을 다루는 매뉴얼이 아닙니다. 이 책은 확률의 바다 위에서 결정론의 등대를 세우고자 하는 엔지니어들을 위한 항해 지침서입니다. 우리는 비결정적인 AI를 통제하고, 모호한 출력을 구조화하며, 끊임없이 검증하고 수정하는 시스템을 구축함으로써, AI를 ’마법’이 아닌 신뢰할 수 있는 ’과학’과 ’공학’의 영역으로 끌어들여야 합니다.

이제 막 ’결정론적 오라클’이라는 성배를 찾아 떠나는 긴 여정의 초입에 들어섰습니다. 이 책이 그 여정의 든든한 나침반이 되기를 바랍니다. 독자 여러분은 이 책을 통해 LLM이라는 길들여지지 않은 야수를, 견고한 소프트웨어 아키텍처의 부품으로 조련하는 구체적인 기술과 통찰을 얻게 될 것입니다.

확률적 혼돈 속에서 공학적 엄밀함을 찾아가는 위대한 엔지니어링의 여정에 여러분을 초대합니다.